/*
 * Created on 2005-3-12
 */
package com.hd123.rumba.user;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;

import net.sf.hibernate.FlushMode;
import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Transaction;

import org.apache.log4j.Logger;

import com.hd123.rumba.cartridge.FVRumbaAdvSys;
import com.hd123.rumba.cartridge.ICartFunctionView;
import com.hd123.rumba.cartridge.ICartridgeMgr;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.exception.DuplicateIdException;
import com.hd123.rumba.exception.ParameterException;
import com.hd123.rumba.runtime.HibernateSession;
import com.hd123.rumba.runtime.Manager;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.runtime.OperateContext;
import com.hd123.rumba.sql.ResultPage;
import com.hd123.rumba.sql.SQLSubquery;
import com.hd123.rumba.util.AccessMode;

/**
 * @author caili
 */
public class PermissionMgr extends Manager implements IPermissionMgr {

  public PermissionMgr() {
    super();
    this.registryClass("com.hd123.rumba.user.IPermission", "com.hd123.rumba.user.Permission");
  }

  public IPermission createPermission(String code, String name) throws HibernateException,
      BusinessException {
    this.checkParameterNotNull(code, "code");
    this.checkParameterNotNull(name, "name");
    IPermission perm = getPermissionByCode(code);
    if (perm != null) {
      throw new DuplicateIdException("已经存在code为" + code + "的权限");
    }
    perm = new Permission();
    perm.setCode(code);
    perm.setName(name);
    return perm;
  }

  public IPermission getPermission(String uuid) throws HibernateException {
    IPermission perm = null;
    if (uuid != null)
      perm = (IPermission) getSession().load(Permission.class, uuid);
    return perm;
  }

  public IPermission getPermissionByCode(String code) throws HibernateException {
    IPermission perm = null;
    if (code != null) {
      List list = getSession().find("from Permission p where p.code=?", code.toUpperCase(),
          Hibernate.STRING);
      if (list.size() > 0) {
        perm = (IPermission) list.get(0);
      }
    }
    return perm;
  }

  public void savePermission(IPermission perm) throws HibernateException, BusinessException {
    if (perm == null) {
      throw new ParameterException("必须的参数perm不能是null");
    }
    if (perm.getUuid() != null) {
      getSession().setFlushMode(FlushMode.COMMIT);
      IPermission eperm = getPermissionByCode(perm.getCode());
      if (eperm != null && !eperm.equals(perm)) {
        throw new DuplicateIdException("已经存在ID为" + perm.getCode() + "的权限");
      }
    }
    perm.setLastModified(new Date());
    getSession().saveOrUpdate(perm);
  }

  public void removePermission(IPermission perm) throws HibernateException, BusinessException {
    if (perm == null) {
      throw new ParameterException("必须的参数perm不能是null");
    }
    getSession().delete("from RolePermission rp where rp.permission.uuid=?", perm.getUuid(),
        Hibernate.STRING);
    getSession().delete("from UserPermission up where up.permission.uuid=?", perm.getUuid(),
        Hibernate.STRING);
    getSession().delete("from PermissionCommission pc where pc.permission.uuid=?", perm.getUuid(),
        Hibernate.STRING);
    getSession().delete(perm);
  }

  public List createAllPermissionsList() throws HibernateException {
    return getSession().find("from Permission p order by p.code");
  }

  public List createUserPermissionsList(IUser user) throws HibernateException, BusinessException {
    Vector v = user.getPermissionIds();
    Collections.sort(v);
    List perms = new ArrayList();
    for (int i = 0; i < v.size(); ++i) {
      String code = (String) v.get(i);
      perms.add(getPermissionByCode(code));
    }
    return perms;
  }

  public ResultPage createAllPermissionsPage(int pageSize, int page) throws Exception {
    SQLSubquery sq = new SQLSubquery();
    sq.addSelect("p");
    sq.addFrom("Permission p");
    sq.addOrder("p.code", "asc");
    return ResultPage.createHibernateResultPage(getSession(), sq, pageSize, page);
  }

  /**
   * 根据类cls定义中PERMISSION_FA_XXX的字段, 生成user是否具有此字段的权限. <br>
   * 返回的AccessMode是一个hashtable, 其元素为 <br>
   * key=PERMISSION_FA_XXX, value=AccessMode.INVISIBLE/READONLY/READWRITE(0/1/2)
   * 
   * @param user
   * @param cls
   * @return
   * @throws IllegalAccessException
   */
  public AccessMode createFieldsAccessMode(IUser user, Class cls) throws IllegalAccessException,
      BusinessException {
    AccessMode am = new AccessMode();
    for (int k = 0; k < 1; ++k) {
      Field[] fields = cls.getDeclaredFields();
      for (int i = 0; i < fields.length; ++i) {
        String name = fields[i].getName(), perm;
        if (name.startsWith("PERMISSION_FA_")) {
          perm = (String) fields[i].get(null);
          if (user == null)
            am.setAccessMode(perm, AccessMode.READWRITE);
          else {
            int result = AccessMode.INVISIBLE;
            if (perm == null)
              result = AccessMode.READWRITE;
            else if (user.hasPermission(perm + CPermission.SUFFIX_PERMISSION_EDIT))/* ".readwrite" */
              result = AccessMode.READWRITE;
            else if (user.hasPermission(perm + CPermission.SUFFIX_PERMISSION_VIEW))/* ".readonly" */
              result = AccessMode.READONLY;
            am.setAccessMode(perm, result);
          }
        }
      }
    }
    return am;
  }

  public List<IPermission> getPermissionsByCartFuncView(String cartFuncViewUuid)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(cartFuncViewUuid, "cartFuncViewUuid");
    List<IPermission> list = getSession().find("from IPermission p where p.cartFuncViewUuid = ?",
        cartFuncViewUuid, Hibernate.STRING);
    return list;
  }

  /**
   * 初始化权限表: 从类cls的定义中得到定义的权限, 添加到权限表中. 例如Domain. <br>
   * 类定义中字段权限的定义为public static final String PERMISSION_FA_name = "xxx"; <br>
   * xxx.readonly和xxxx.readwrite将被添加到权限表中 类定义中字段其它的定义为public static final String
   * PERMISSION_name = "xxx"; <br>
   * xxx将被添加到权限表中
   * 
   * @param cls
   * @throws Exception
   */
  public void initPermissionsT(Class cls) throws Exception {
    List list = createAllPermissionsList();
    Hashtable h = new Hashtable(list.size());
    for (int i = 0; i < list.size(); ++i) {
      Permission perm = (Permission) list.get(i);
      h.put(perm.getCode(), perm);
    }

    Transaction tx;
    tx = HibernateSession.beginTransaction();
    addPermissions(h, cls);
    HibernateSession.commit(tx);
  }

  /**
   * 供initPermissions调用, 用于初始化权限表
   * 
   * @param permissions
   * @param cls
   * @throws Exception
   */
  private void addPermissions(Hashtable permissions, Class cls) throws Exception {
    Field[] fields = cls.getDeclaredFields();

    // 查找构件包前缀，即名为“FUNCV_PREFIX”的常量取值。由此查找构件包。
    String prefix = FVRumbaAdvSys.FUNCV_PREFIX; // 默认所属构件包视图，兼容老权限定义方式。
    Integer providerType = CPermissionProvider.VALUE_TYPE_UNKNOWN;
    String providerClass = cls.getName();
    String providerCaption = null;
    for (int i = 0; i < fields.length; i++) {
      String name = fields[i].getName();
      if ("FUNCV_PREFIX".equals(name))
        prefix = (String) fields[i].get(null);
      else if ("CAPTION_CLASS".equals(name)) {
        providerType = CPermissionProvider.VALUE_TYPE_ENTITY;
        providerCaption = (String) fields[i].get(null);
      } else if ("CAPTION_VIEW".equals(name)) {
        providerType = CPermissionProvider.VALUE_TYPE_ACTION;
        providerCaption = (String) fields[i].get(null);
      }
    }

    ICartridgeMgr cartMgr = (ICartridgeMgr) NamingMgr.getInstance().lookupMgr(ICartridgeMgr.class);
    ICartFunctionView funcv = cartMgr.getFunctionViewByPrefix(prefix);
    if (funcv == null)
      throw new BusinessException("找不到指定的构件包功能视图(" + prefix + ")。");

    for (int i = 0; i < fields.length; ++i) {
      String name = fields[i].getName();
      String perm;
      String fieldCaption = null;
      if (name.startsWith("PERMISSION_FA_")) {
        perm = (String) fields[i].get(null);
        String[] ss = perm.split("\\.");
        if (ss.length > 0)
          fieldCaption = ss[ss.length - 1];
        addPermission(permissions, perm + CPermission.SUFFIX_PERMISSION_VIEW, funcv, providerType,
            providerClass, providerCaption, fieldCaption);/* ".readonly" */
        addPermission(permissions, perm + CPermission.SUFFIX_PERMISSION_EDIT, funcv, providerType,
            providerClass, providerCaption, fieldCaption);/* ".readwrite" */
      } else if (name.startsWith("PERMISSION_")) {
        perm = (String) fields[i].get(null);
        addPermission(permissions, perm, funcv, providerType, providerClass, providerCaption,
            fieldCaption);
      }
    }
  }

  public void addPermissionsForRoleT(IRole role, Class cls) throws BusinessException,
      HibernateException {
    PermissionMgr perMgr = new PermissionMgr();
    RoleMgr roleMgr = new RoleMgr();
    IUserMgr userMgr = (IUserMgr) NamingMgr.getInstance().lookupMgr(IUserMgr.class);
    IPermission perm = null;
    OperateContext operate = new OperateContext(userMgr.getSysUser(), new Date());
    Transaction tx = getSession().beginTransaction();
    try {
      for (int k = 0; k < 1; ++k) {
        Field[] fields = cls.getDeclaredFields();
        for (int i = 0; i < fields.length; ++i) {
          String name = fields[i].getName(), permCode;
          if (name.startsWith("PERMISSION_FA_")) {
            permCode = (String) fields[i].get(null);
            perm = perMgr.getPermissionByCode(permCode + ".查看权");
            if (perm != null)
              roleMgr.assignPermissionToRole(perm, role, operate);

            perm = perMgr.getPermissionByCode(permCode + ".修改权");
            if (perm != null)
              roleMgr.assignPermissionToRole(perm, role, operate);
          } else if (name.startsWith("PERMISSION_")) {
            permCode = (String) fields[i].get(null);
            perm = perMgr.getPermissionByCode(permCode);
            if (perm != null)
              roleMgr.assignPermissionToRole(perm, role, operate);
          }
        }
      }
      tx.commit();
    } catch (Exception e) {
      tx.rollback();
      if (e instanceof HibernateException)
        throw (HibernateException) e;
      else
        throw new BusinessException(e);
    } finally {
      getSession().flush();
    }
  }

  /**
   * 被addPermissions调用, 用于初始化权限表
   * 
   * @param permissions
   * @param permId
   * @param cart
   * @throws Exception
   */
  private void addPermission(Hashtable permissions, String permId, ICartFunctionView funcv,
      Integer providerType, String providerClass, String providerCaption, String fieldCaption)
      throws Exception {
    IPermission perm = null;
    if (!permissions.containsKey(permId)) {
      String permName = permId;
      if (permName.startsWith(funcv.getPrefix() + "."))
        permName = permName.substring(funcv.getPrefix().length() + 1);
      perm = createPermission(permId, permName);
      perm.setCartFuncViewUuid(funcv.getUuid());
      if (perm.getProvider() == null)
        perm.setProvider(new PermissionProvider());
      perm.getProvider().setType(providerType);
      perm.getProvider().setClassName(providerClass);
      perm.getProvider().setCaption(providerCaption);
      perm.setFieldCaption(fieldCaption);
      savePermission(perm);
      permissions.put(perm.getCode(), perm);
      Logger.getLogger(this.getClass()).debug("permission created: " + perm.getCode());
    }
  }
}
